/**
 **************************************************************************
 * @file     ssd1306.h
 * @brief    ssd1306 驱动
 **************************************************************************
 * MCU: AT32F413CCU7
 * IO分配：
 * PB10 -> I2C2_SCL
 * PB11 -> I2C2_SDA
 * 所用 IIC 为 I2C2
 **************************************************************************
 *
 */
#pragma once

#include <string>
#include "i2c_application.h"
#include "xtp_type.h"
#include "font.h"

namespace OLED
{

#define I2Cx_DMA_TX_IRQn DMA1_Channel4_IRQn

    //================ SSD1306 命令定义
#define DISPLAY_OFF 0xAE
#define DISPLAY_ON 0xAF
#define NORMAL_DISPLAY 0xA6
#define INVERT_DISPLAY 0xA7
#define ENTIRE_DISPLAY 0xA5 // 强制全屏显示
#define GDDRAM_DISPLAY 0xA4 // 显示 GDDRAM 中的内容

    enum class Color : uint8_t
    {
        Black = 0x00,
        White = 0x01,
        Inverse = 0x02
    };

    enum class ColorMode : uint8_t
    {
        NORMAL = 0x00,
        INVERT
    };

    enum class DegMode : uint8_t
    {
        Deg_0 = 0x00,
        Deg_180,
        Mirror
    };

    class SSD1306
    {

    private:
        static const uint32_t kTimeOut = 0xFFFFFFFF;
        static const uint8_t kCmd = 0x00;  // D/C# 位置1 0b0x00_0000 x为0命令，x为1数据
        static const uint8_t kData = 0x40; // D/C# 位置1 0b0x00_0000 x为0命令，x为1数据
        static const uint8_t kSSD1306Width = 128;
        static const uint8_t kSSD1306Height = 64;
        static const uint16_t kBufferSize = kSSD1306Width * kSSD1306Height / 8;
        uint32_t m_iic_speed;
        uint8_t m_address;
        uint8_t m_buffer[kBufferSize];
        Color m_color;
        ColorMode m_color_mode;
        DegMode m_deg_mode;
        bool m_inverted;
        uint8_t m_current_x;
        uint8_t m_current_y;

    private:
        crm_periph_clock_type m_iic_periph_clock;
        crm_periph_clock_type m_sda_periph_clock;
        crm_periph_clock_type m_clk_periph_clock;
        i2c_handle_type* m_hi2cx;
        i2c_type* m_iicx;
        gpio_type* m_clk_port;
        gpio_type* m_sda_port;
        uint32_t m_clk_pin;
        uint32_t m_sda_pin;

    public: // 图形操作相关函数
        SSD1306(
            crm_periph_clock_type _iic_periph_clock,
            crm_periph_clock_type _sda_periph_clock,
            crm_periph_clock_type _clk_periph_clock,
            i2c_type* _iicx,
            uint8_t _addr,
            i2c_handle_type* _hi2cx,
            gpio_type* _clk_port,
            gpio_type* _sda_port,
            uint32_t _clk_pin,
            uint32_t _sda_pin
        );
        void init(void);
        void clear(void);
        void update(void);
        void fill(void);
        void setColor(Color _color);
        Color getColor(void);
        void setColorMode(ColorMode _color_mode);
        void setDegMode(DegMode _deg_mode);
        void on(void);
        void off(void);
        void drawPixel(uint8_t x, uint8_t y);
        void setInverted(bool _inverse);
        void drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1);
        void drawHorizontalLine(int16_t x, int16_t y, int16_t length);
        void drawVerticalLine(int16_t x, int16_t y, int16_t length);
        void drawRectangle(int16_t x, int16_t y, int16_t width, int16_t height);
        void drawFillRectangle(int16_t xMove, int16_t yMove, int16_t width, int16_t height);
        void drawTriangle(u16 x1, u16 y1, u16 x2, u16 y2, u16 x3, u16 y3);
        void drawFillTriangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t x3, uint16_t y3);
        void drawCircle(int16_t x0, int16_t y0, int16_t radius);
        void drawFillCircle(int16_t x0, int16_t y0, int16_t radius);
        void drawCircleQuads(int16_t x0, int16_t y0, int16_t radius, uint8_t quads);
        void drawProgressBar(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint8_t progress);
        char writeChar(char _ch, FontDef _font);
        void writeString(std::string _str, FontDef _font);
        void writeNumber(int _num, FontDef _font);
        void writeFloat(float _value, FontDef _font);
        void writeChinese(uint8_t _size, uint8_t _index);
        void setCursor(uint8_t x, uint8_t y);



    public: // 硬件相关函数
        uint8_t getAddress(void);
        i2c_type* getIICx(void);
        gpio_type* getClkPort(void);
        gpio_type* getSdaPort(void);
        crm_periph_clock_type getI2CPeriphClock(void);
        crm_periph_clock_type getClkPeriphClock(void);
        crm_periph_clock_type getSdaPeriphClock(void);
        uint32_t getClkPin(void);
        uint32_t getSdaPin(void);
        uint32_t getI2CSpeed(void);
        void setI2CSpeed(uint32_t _speed);



    private:
        void m_send_data(uint8_t* _data, uint16_t _size);
        void m_send_command(uint8_t _command);

    public:
        static const uint8_t kCenterX = SSD1306::kSSD1306Width / 2;
        static const uint8_t kCenterY = SSD1306::kSSD1306Height / 2;
        static const uint8_t kMinX = 0;
        static const uint8_t kMaxX = SSD1306::kSSD1306Width;
        static const uint8_t kMinY = 0;
        static const uint8_t kMaxY = SSD1306::kSSD1306Height;
    };

} /* OLED namespace END! */
